import numpy as np

from init import *
from sklearn.decomposition import PCA
from skfuzzy.cluster import cmeans
# from icmeans import *
import copy
from collections import Counter
import geatpy as ea
from init import *
import pandas as pd

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False


# def FCM(X, c_clusters, m=2, eps=0.01):
#     membership_mat = np.random.random((len(X), c_clusters))
#     membership_mat = np.divide(membership_mat, np.sum(membership_mat, axis=1)[:, np.newaxis])
#
#     while True:
#         working_membership_mat = membership_mat ** m
#         Centroids = np.divide(np.dot(working_membership_mat.T, X),
#                               np.sum(working_membership_mat.T, axis=1)[:, np.newaxis])
#
#         n_c_distance_mat = np.zeros((len(X), c_clusters))
#         for i, x in enumerate(X):
#             for j, c in enumerate(Centroids):
#                 n_c_distance_mat[i][j] = np.linalg.norm(x - c, 2)
#
#         new_membership_mat = np.zeros((len(X), c_clusters))
#
#         for i, x in enumerate(X):
#             for j, c in enumerate(Centroids):
#                 new_membership_mat[i][j] = 1. / np.sum((n_c_distance_mat[i][j] / n_c_distance_mat[i]) ** (2 / (m - 1)))
#         if np.sum(abs(new_membership_mat - membership_mat)) < eps:
#             break
#         membership_mat = new_membership_mat
#     return np.argmax(new_membership_mat, axis=1)


def get_feature(img_data, flag, ksize):
    '''
    对图像的特征进行提取
    :param img_data: 图像信息
    :param flag: 奇数点还是偶数点
    :return:
    '''
    row, col = img_data.shape
    size = int((row * col) / 2)
    F = np.zeros((ksize, size))

    # 预测点
    predict = np.zeros((row, row))
    # 误差值
    erromap = np.zeros((row, row))
    index = 0
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            # 像素上下左右四个像素
            v1 = int(img_data[i - 1][j])
            v2 = int(img_data[i][j - 1])
            v3 = int(img_data[i + 1][j])
            v4 = int(img_data[i][j + 1])
            # 选中点
            x = int(img_data[i][j])
            # 其他九个点
            v5 = int(img_data[i - 2][j - 1])
            v6 = int(img_data[i - 1][j - 2])
            v7 = int(img_data[i + 1][j - 2])
            v8 = int(img_data[i + 2][j - 1])
            v9 = int(img_data[i + 2][j + 1])
            v10 = int(img_data[i + 1][j + 2])
            v11 = int(img_data[i - 1][j + 2])
            v12 = int(img_data[i - 2][j + 1])
            p1 = (math.modf(np.average([v1, v2, v3, v4])))[0]
            p = np.ceil(np.average([v1, v2, v3, v4])) if p1 >= 0.5 else np.floor(np.average([v1, v2, v3, v4]))
            # if flag == 0 :
            #     p1 = (math.modf(np.average([v1, v2, v3, v4])))[0]
            #     p = np.ceil(np.average([v1, v2, v3, v4])) if p1 >= 0.5 else np.floor(np.average([v1, v2, v3, v4]))
            #
            #     h1 = int(img_data[i-1][j+1]) -int(img_data[i-1][j-1])
            #     h2 = int(img_data[i][j+1]) -int(img_data[i][j-1])
            #     h3 = int(img_data[i+1][j+1]) -int(img_data[i+1][j-1])
            #     h = np.sum(h1+2*h2+h3)
            #     vi1 = int(img_data[i +1][j - 1]) - int(img_data[i - 1][j - 1])
            #     vi2 = int(img_data[i+1][j + 1]) - int(img_data[i-1][j])
            #     vi3 = int(img_data[i + 1][j + 1]) - int(img_data[i - 1][j + 1])
            #     v = np.sum(vi1 + 2 * vi2 + vi3)
            #     f1 = np.sqrt(h**2+v**2)
            if flag == 0:
                if np.mod(i + j, 2) == 0:
                    # 新点
                    x1 = int(img_data[i + 1][j + 1])
                    x2 = int(img_data[i + 1][j - 1])
                    x3 = int(img_data[i - 1][j + 1])
                    x4 = int(img_data[i + 1][j - 1])
                    x5 = int(img_data[i][j + 2])
                    x6 = int(img_data[i][j - 2])
                    h = np.round((6 * np.sum([x1 - x2, x3 - x4]) + 2 * np.sum([x5 - x6])) / 4)
                    x1 = int(img_data[i + 1][j + 1])
                    x2 = int(img_data[i - 1][j + 1])
                    x3 = int(img_data[i + 1][j - 1])
                    x4 = int(img_data[i - 1][j - 1])
                    x5 = int(img_data[i + 2][j])
                    x6 = int(img_data[i - 2][j])
                    v = np.round((6 * np.sum([x1 - x2, x3 - x4]) + 2 * np.sum([x5 - x6])) / 4)
                if np.mod(i + j, 2) == 1:
                    y1 = int(img_data[i + 2][j + 1])
                    y2 = int(img_data[i + 2][j - 1])
                    y3 = int(img_data[i - 2][j + 1])
                    y4 = int(img_data[i + 2][j - 1])
                    y5 = int(img_data[i + 1][j + 2])
                    y6 = int(img_data[i + 1][j - 2])
                    y7 = int(img_data[i - 1][j + 2])
                    y8 = int(img_data[i - 1][j - 2])
                    y9 = int(img_data[i][j + 1])
                    y10 = int(img_data[i][j - 1])
                    h = np.round(
                        (np.sum([y1 - y2, y3 - y4]) + np.sum([y5 - y6, y7 - y8]) + 10 * np.sum([y9 - y10])) / 4)
                    y1 = int(img_data[i + 1][j + 2])
                    y2 = int(img_data[i - 1][j + 2])
                    y3 = int(img_data[i + 1][j - 2])
                    y4 = int(img_data[i - 1][j - 2])
                    y5 = int(img_data[i + 2][j + 1])
                    y6 = int(img_data[i - 2][j + 1])
                    y7 = int(img_data[i + 2][j - 1])
                    y8 = int(img_data[i - 2][j - 1])
                    y9 = int(img_data[i + 1][j])
                    y10 = int(img_data[i - 1][j])
                    v = np.round(
                        (np.sum([y1 - y2, y3 - y4]) + np.sum([y5 - y6, y7 - y8]) + 10 * np.sum([y9 - y10])) / 4)

            if flag == 1:
                if np.mod(i + j, 2) == 1:
                    # 新点
                    x1 = int(img_data[i + 1][j + 1])
                    x2 = int(img_data[i + 1][j - 1])
                    x3 = int(img_data[i - 1][j + 1])
                    x4 = int(img_data[i + 1][j - 1])
                    x5 = int(img_data[i][j + 2])
                    x6 = int(img_data[i][j - 2])
                    h = np.round((6 * np.sum([x1 - x2, x3 - x4]) + 2 * np.sum([x5 - x6])) / 4)
                    x1 = int(img_data[i + 1][j + 1])
                    x2 = int(img_data[i - 1][j + 1])
                    x3 = int(img_data[i + 1][j - 1])
                    x4 = int(img_data[i - 1][j - 1])
                    x5 = int(img_data[i + 2][j])
                    x6 = int(img_data[i - 2][j])
                    v = np.round((6 * np.sum([x1 - x2, x3 - x4]) + 2 * np.sum([x5 - x6])) / 4)
                if np.mod(i + j, 2) == 0:
                    y1 = int(img_data[i + 2][j + 1])
                    y2 = int(img_data[i + 2][j - 1])
                    y3 = int(img_data[i - 2][j + 1])
                    y4 = int(img_data[i + 2][j - 1])
                    y5 = int(img_data[i + 1][j + 2])
                    y6 = int(img_data[i + 1][j - 2])
                    y7 = int(img_data[i - 1][j + 2])
                    y8 = int(img_data[i - 1][j - 2])
                    y9 = int(img_data[i][j + 1])
                    y10 = int(img_data[i][j - 1])
                    h = np.round(
                        (np.sum([y1 - y2, y3 - y4]) + np.sum([y5 - y6, y7 - y8]) + 10 * np.sum([y9 - y10])) / 4)
                    y1 = int(img_data[i + 1][j + 2])
                    y2 = int(img_data[i - 1][j + 2])
                    y3 = int(img_data[i + 1][j - 2])
                    y4 = int(img_data[i - 1][j - 2])
                    y5 = int(img_data[i + 2][j + 1])
                    y6 = int(img_data[i - 2][j + 1])
                    y7 = int(img_data[i + 2][j - 1])
                    y8 = int(img_data[i - 2][j - 1])
                    y9 = int(img_data[i + 1][j])
                    y10 = int(img_data[i - 1][j])
                    v = np.round(
                        (np.sum([y1 - y2, y3 - y4]) + np.sum([y5 - y6, y7 - y8]) + 10 * np.sum([y9 - y10])) / 4)
            t0 = np.array(
                [img_data[i][j - 1], img_data[i][j + 1], np.round((img_data[i][j - 1] + img_data[i][j + 1]) / 2)])
            t45 = np.array(
                [img_data[i][j + 1], img_data[i + 1][j], np.round((img_data[i][j + 1] + img_data[i + 1][j]) / 2)])
            t90 = np.array(
                [img_data[i + 1][j], img_data[i - 1][j], np.round((img_data[i + 1][j] + img_data[i - 1][j]) / 2)])
            t135 = np.array(
                [img_data[i][j - 1], img_data[i + 1][j], np.round((img_data[i][j - 1] + img_data[i + 1][j]) / 2)])
            u = np.mean([(img_data[i][j - 1] + img_data[i][j + 1]) / 2,
                         (img_data[i][j + 1] + img_data[i + 1][j]) / 2,
                         (img_data[i + 1][j] + img_data[i - 1][j]) / 2,
                         (img_data[i][j - 1] + img_data[i + 1][j]) / 2])
            t1 = np.sum(np.square(t0 - u))
            t2 = np.sum(np.square(t45 - u))
            t3 = np.sum(np.square(t90 - u))
            t4 = np.sum(np.square(t135 - u))

            V = [v1, v2, v3, v4]
            # 特征七
            if j - 3 > 0 and j + 3 < 511:
                x7arr = np.array([img_data[i][j - 3], img_data[i][j - 1], img_data[i][j + 1], img_data[i][j + 3]])
            else:
                x7arr = np.array([img_data[i][j - 1], img_data[i][j + 1]])
            u1 = np.mean(x7arr)
            # 特征八
            if i - 3 > 0 and i + 3 < 511:
                x8arr = np.array([img_data[i - 3][j], img_data[i - 1][j], img_data[i + 1][j], img_data[i + 3][j]])
            else:
                x8arr = np.array([img_data[i - 1][j], img_data[i + 1][j]])
            u2 = np.mean(x8arr)
            # 特征十
            Vu = np.array([img_data[i - 1][j - 2], img_data[i - 2][j - 1], img_data[i][j - 1],
                           img_data[i - 1][j], img_data[i - 2][j + 1], img_data[i][j + 1],
                           img_data[i - 1][j + 2]]
                          )
            Vb = np.array([img_data[i + 1][j - 2], img_data[i][j - 1], img_data[i + 2][j - 1],
                           img_data[i + 1][j], img_data[i][j + 1], img_data[i + 2][j + 1],
                           img_data[i + 1][j + 2]]
                          )
            Hl = np.array([img_data[i - 2][j - 1], img_data[i - 1][j - 2], img_data[i - 1][j],
                           img_data[i][j - 1], img_data[i + 1][j - 2], img_data[i + 1][j],
                           img_data[i + 2][j - 1]]
                          )
            Hr = np.array([img_data[i - 2][j + 1], img_data[i - 1][j], img_data[i - 1][j + 2],
                           img_data[i][j + 1], img_data[i + 1][j], img_data[i + 1][j + 2],
                           img_data[i + 2][j + 1]]
                          )
            # 特征十
            V10 = np.array([img_data[i - 2][j - 1], img_data[i - 2][j + 1], img_data[i - 1][j - 2],
                            img_data[i - 1][j], img_data[i - 1][j + 2], img_data[i][j - 1],
                            img_data[i][j + 1], img_data[i + 1][j - 2], img_data[i + 1][j],
                            img_data[i + 1][j + 2], img_data[i + 2][j - 1], img_data[i + 2][j - 1]])

            u3 = np.mean(V10)
            # 特征十三
            point1 = np.mean([img_data[i - 2][j - 1], img_data[i - 1][j - 2], img_data[i][j - 1], img_data[i - 1][j]])
            point2 = np.mean([img_data[i - 1][j], img_data[i - 2][j + 1], img_data[i - 1][j + 2], img_data[i][j + 1]])
            point3 = np.mean([img_data[i + 1][j - 2], img_data[i][j - 1], img_data[i + 1][j], img_data[i + 2][j - 1]])
            point4 = np.mean([img_data[i + 1][j], img_data[i + 2][j + 1], img_data[i][j + 1], img_data[i + 1][j + 2]])
            Varr = np.array([v1, v2, v3, v4, point1, point2, point3, point4])
            temp1 = np.sign(Varr - img_data[i][j])
            temp = np.where(np.sign(Varr - img_data[i][j]) == -1)[0]
            temp1[temp] = 0

            f1 = np.sqrt(v ** 2 + h ** 2)
            f2 = np.sqrt(np.sum([t1, t2, t3, t4]))
            f3 = np.mean(V)
            f4 = np.max(V)
            f5 = np.min(V)
            f6 = np.sum(np.square(V - f3))
            f7 = np.sum(x7arr - u1)
            f8 = np.sum(x8arr - u2)
            f9 = np.sum([np.abs(Vu - Vb), np.abs(Hl - Hr)])
            f10 = np.sum(np.abs(V10 - u3))
            f11 = np.abs(img_data[i - 2][j + 1] - img_data[i - 1][j]) \
                  + np.abs(img_data[i - 1][j] - img_data[i][j - 1]) \
                  + np.abs(img_data[i][j - 1] - img_data[i + 1][j - 2]) \
                  + np.abs(img_data[i - 1][j + 2] - img_data[i][j - 1]) \
                  + np.abs(img_data[i][j - 1] - img_data[i + 1][j]) \
                  + np.abs(img_data[i + 1][j] - img_data[i + 2][j - 1])
            f12 = np.abs(img_data[i - 2][j + 1] - img_data[i - 1][j]) \
                  + np.abs(img_data[i - 1][j] - img_data[i][j - 1]) \
                  + np.abs(img_data[i][j - 1] - img_data[i + 1][j - 2]) \
                  + np.abs(img_data[i - 1][j + 2] - img_data[i][j + 1]) \
                  + np.abs(img_data[i][j + 1] - img_data[i + 1][j]) \
                  + np.abs(img_data[i + 1][j] - img_data[i + 2][j - 1])
            f13 = np.sum(temp1)

            a = [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13]

            if np.mod(i + j, 2) == 0 and flag == 0:
                # print(a)
                F[:, index] = a
                index += 1
                erromap[i][j] = int(img_data[i][j]) - int(p)
            if np.mod(i + j, 2) == 1 and flag == 1:
                F[:, index] = a
                index += 1
                erromap[i][j] = int(img_data[i][j]) - int(p)
    print('index', index)
    print(F.shape)
    pd.DataFrame(F).to_csv('./F.csv')
    file_name = 'F.mat'
    scio.savemat(file_name, {'aa': F.T})
    pca = PCA(n_components=3)
    data = pca.fit_transform(F.T)

    data = np.array(data)
    # enter, u, u0, d, jm, p, fpc = cmeans(data.T, m=2, c=16, error=0.5, maxiter=10000)
    center, u, u0, d, jm, p, fpc = cmeans(data.T, 5, 2, error=0.00001, maxiter=100)
    label = np.argmax(u, axis=0)
    # label = fuzzy(data.T,16,2)
    # label = np.array(label).flatten()
    print('label', label)
    print(np.unique(label))
    return label, erromap


def complexity_map(img_data, label, flags):
    cm = np.zeros(img_data.shape)
    A, B = img_data.shape
    count = 0
    for i in range(2, A - 2):
        for j in range(2, B - 2):
            if np.mod(i + j, 2) == 0 and flags == 0:
                cm[i][j] = int(label[count]) + 1
                count = count + 1
            if np.mod(i + j, 2) == 1 and flags == 1:
                cm[i][j] = int(label[count]) + 1
                count = count + 1
    return cm


def cal_entropy(imgs, label, ks, flags):
    A, B = imgs.shape
    his = []
    count = 0
    entropy = []
    for i in range(ks):
        his.append([])
    for i in range(2, A - 2):
        for j in range(2, B - 2):
            # v1 = int(imgs[i - 1][j])
            # v2 = int(imgs[i + 1][j])
            # v3 = int(imgs[i][j + 1])
            # v4 = int(imgs[i][j - 1])
            # e = np.ceil(np.average([v1, v2, v3, v4])) - int(imgs[i][j])
            if flags == 0 and np.mod(i + j, 2) == 0:
                his[label[count]].append(int(imgs[i][j]))
                count = count + 1
            elif flags == 1 and np.mod(i + j, 2) == 1:
                his[label[count]].append(int(imgs[i][j]))
                count = count + 1

    for i in range(ks):
        e = 0
        c = Counter(his[i])
        total = len(his[i])
        for j in c.values():
            pro = int(j) / total
            e = e + pro * math.log(1 / pro, 2)
        entropy.append(e)
    print(entropy)
    entropy_sort = sorted(entropy)
    cor = []
    labels = []
    print(entropy_sort)
    for i in range(ks):
        for j in range(ks):
            if entropy[i] == entropy_sort[j]:
                cor.append(j)
                entropy_sort[j] = -1
                break
    print(cor)
    for i in label:
        labels.append(cor[i])
    # legend = []
    # fig = []
    # frequency = list(range(ks))
    # new_name = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
    # for i in range(ks):
    #     legend.append('l=' + str(cor[i]))
    #     fig.append(str(cor[i]))
    #     # print(len(his[i]))
    #     frequency[cor[i]] = int(len(his[cor[i]]))
    # plt.grid(ls=':')
    # plt.bar(range(ks), frequency, tick_label=new_name, color='b')
    # plt.title('The distribution of pixels')
    # plt.xlabel('Neuron')
    # plt.ylabel('Population')
    # plt.show()
    return labels, cor


def cal_aux(checklist, data_length, scale, re, lcm, flags):
    cl = 0
    test = []
    for i in range(16):
        test.append(i)
    checklist = np.array(checklist) + 1
    # checklist = np.array(test)+1
    print('incheck', checklist)
    a = np.ceil(np.log2(np.max(checklist)))
    if flags == 0:
        for i in range(16):
            #
            if re[i] == 250:
                scale = scale - 1
            if checklist[i] != i:
                cl = cl + np.ceil(np.log2(checklist[i]))
        if np.sum(lcm) == 0:
            aux = scale * 3 + 4 + 1 + 17 + cl + 4
        else:
            aux = scale * 3 + 4 + 1 + data_length * 8 + 17 + 17 + cl + 4
    if flags == 1:  # 根据寻优的bins更新辅助信息的长度
        for i in range(16):
            if re[i] < 250 and checklist[i] > i:
                cl = cl + np.ceil(np.log2(checklist[i]))
            if re[i] == 250:
                scale = scale - 1
                print('scale', scale)
        if np.sum(lcm) == 0:
            aux = scale * 3 + 4 + 1 + 17 + cl + 4
        else:
            aux = scale * 3 + 4 + 1 + data_length * 8 + 17 + 17 + cl + 4
    print('The aux is ', flags, ' ', aux)
    return aux


def re_hs(k, row, col, cm, flag, em):
    Hs = np.zeros((511, k))
    # index = 0
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            if np.mod(i + j, 2) == 0 and flag == 0:
                Hs[int(em[i][j] + 254)][int(cm[i][j]) - 1] += 1
                # index += 1
            if np.mod(i + j, 2) == 1 and flag == 1:
                Hs[int(em[i][j] + 254)][int(int(cm[i][j])) - 1] += 1
                # index += 1
    return Hs


def insert_msg(em, cm, bin, img_hide3, secret, ec3, flag3):
    '''
        em误差矩阵
        Dbis复杂度矩阵
        bin最佳区间
        img_hide图形矩阵
        secret嵌入矩阵
        插入需要插入的信息
    '''
    index = 0
    index2 = 0
    row, col = img_hide3.shape
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            if np.mod(i + j, 2) == 0 and flag3 == 0 and ec3 > 0:
                ks = cm[i][j] - 1
                if em[i][j] == bin[int(ks)]:
                    ec3 = ec3 - 1
                    img_hide3[i][j] += secret[i][j]
                    if secret[i][j] == 1:
                        index2 += 1
                if em[i][j] == -bin[int(ks)] - 1:
                    ec3 = ec3 - 1
                    img_hide3[i][j] -= secret[i][j]
                    if secret[i][j] == 1:
                        index2 += 1
                if em[i][j] > bin[int(ks)]:
                    img_hide3[i][j] += 1
                    index += 1
                if em[i][j] < -bin[int(ks)] - 1:
                    img_hide3[i][j] -= 1
                    index += 1
            if np.mod(i + j, 2) == 1 and flag3 == 1 and ec3 > 0:
                ks = cm[i][j] - 1
                if em[i][j] == bin[int(ks)]:
                    ec3 = ec3 - 1
                    img_hide3[i][j] += secret[i][j]
                    if secret[i][j] == 1:
                        index2 += 1
                if em[i][j] == -bin[int(ks)] - 1:
                    ec3 = ec3 - 1
                    img_hide3[i][j] -= secret[i][j]
                    if secret[i][j] == 1:
                        index2 += 1
                if em[i][j] > bin[int(ks)]:
                    img_hide3[i][j] += 1
                    index += 1
                if em[i][j] < -bin[int(ks)] - 1:
                    img_hide3[i][j] -= 1
                    index += 1

    print("偏移数量", index)
    print('偏移点数量', index2)
    return img_hide3, ec3


def danci(danci_img, flags, ks, ecfinals):
    danci_img, lcm, halfsize, data = Over_flow(danci_img, flags)
    # 数组长度
    data_length = len(data)
    # 获取图片的坐标的长宽
    row, col = danci_img.shape
    # 初始图像数据,获取误差以及按照图像的复杂度进行分类
    label, em = get_feature(danci_img, flags, 10)
    label, check = cal_entropy(danci_img, label, ks, flags)
    # print(label)
    # pd.DataFrame(em).to_csv('./em.csv')
    cm = complexity_map(danci_img, label, flags)
    hs = re_hs(16, row, col, cm, flags, em)
    R = np.zeros(16)
    anx = cal_aux(check, data_length, ks, R, lcm, flags)
    # anx = test[0]
    ec1 = ecfinals / 2 + anx
    bins = searchbins(hs, ec1)
    print('bin', bins)
    '''
        通过最佳嵌入点判断是否存储了两个以上的250（即无穷大）
        如果超过两个以上需要重新计算辅助信息大小
    '''
    scale = 16
    anx = cal_aux(check, data_length, scale, bins, lcm, flags)
    # anx = test[1]
    ec1 = ecfinals / 2 + anx
    # # img_hide记录修改过后的图像坐标
    img_hide1 = copy.deepcopy(danci_img)
    # # 嵌入的数据secrt_msg[0][index]
    secret_info = secret_msg(row, col)
    # # 嵌入数据之后的误差图像
    img_hide1, ec1 = insert_msg(em, cm, bins, img_hide1, secret_info, ec1, flags)
    # # lsb插入辅助信息
    anx_secret = secret_msg(row, col)
    img_hide1 = Lsb_insert(row, col, anx, img_hide1, flags, anx_secret)
    return img_hide1, ec1


def plt_make(psnr):
    x = np.linspace(0.01, 0.13, 9)
    y = psnr
    plt.plot(x, y, '-r', label='psnr')
    plt.plot(x, y, '.b')
    plt.title('lena psnr')
    plt.xlabel('ec', color='#1C2833')
    plt.ylabel('psnr', color='#1C2833')
    plt.legend(loc='upper left')
    plt.grid()
    plt.show()


def make_hs(label, ks, img, flag, cor):
    Hs = np.zeros((ks, 256))
    row, col = img.shape
    index = 0
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            cor = np.array(cor)
            # index2 = np.where(cor == label[index])[0][0]
            if np.mod(i + j, 2) == 0 and flag == 0:
                Hs[int(label[index])][img[i][j]] += 1
                # Hs[index2][img[i][j]] += 1
                index += 1
            if np.mod(i + j, 2) == 1 and flag == 1:
                Hs[int(label[index])][img[i][j]] += 1
                # Hs[index2][img[i][j]] += 1
                index += 1
    return Hs


class MyProblem(ea.Problem):  # 继承Problem父类
    def __init__(self, data, index_length, ec):
        name = 'MyProblem'  # 初始化name（函数名称，可以随意设置）
        M = 1  # 初始化M（目标维数）
        maxormins = [-1]  # 初始化maxormins（目标最小最大化标记列表，1：最小化该目标；-1：最大化该目标）
        Dim = index_length  # 初始化Dim（决策变量维数）
        varTypes = [1] * Dim  # 初始化varTypes（决策变量的类型，元素为0表示对应的变量是连续的；1表示是离散的）
        lb = [data[0]] * Dim  # 决策变量下界
        ub = [data[1]] * Dim  # 决策变量上界
        lbin = [1] * Dim  # 决策变量下边界（0表示不包含该变量的下边界，1表示包含）
        ubin = [1] * Dim  # 决策变量上边界（0表示不包含该变量的上边界，1表示包含）
        # 调用父类构造方法完成实例化
        ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)
        self.left_index = data[0]
        self.right_index = data[1]
        self.Hs = data[2]

    def aimFunc(self, pop):  # 目标函数
        Vars = pop.Phen  # 得到决策变量矩阵
        x = Vars.astype(int)  # 得到决策变量矩阵
        # print("x", x.shape)
        # print(Vars.shape)
        # x1 = Vars[:, [0]]
        # print()
        left_indexs = self.left_index
        Hs = self.Hs
        right_indexs = self.right_index
        # print('leftindex,rightindex',left_indexs,right_indexs)
        row, col = x.shape
        capity = np.zeros(row)
        dist = np.ones(row) * 100000000
        # print('left',LeftX.shape)
        for i in range(row):
            X = x[i, :]
            X = np.sort(X)
            for j in range(left_indexs):
                capity[i] += Hs[X[j]]
                dist[i] += np.sum(Hs[:X[j]]) + Hs[X[j]] / 2
            for j in range(left_indexs, len(X)):
                capity[i] += Hs[X[j]]
                dist[i] += np.sum(Hs[X[j]:]) + Hs[X[j]] / 2
            # for j in range(len(X)):
            #     capity[i] += Hs[X[j]]
            #     if X[j]>=128:
            #         dist[i] += np.sum(Hs[X[j]:]) + Hs[X[j]] / 2
            #     else:
            #         dist[i] += np.sum(Hs[:X[j]]) + Hs[X[j]] / 2

        # pop.CV = Hs[]
        # opera = capity / dist
        # print('oper',opera.shape)
        pop.ObjV = np.vstack([capity]).T  # 计算目标函数值，赋值给pop种群对象的ObjV属性

    # def calReferObjV(self):  # 设定目标数参考值（本问题目标函数参考值设定为理论最优值）
    #     referenceObjV = np.array([[2.5]])
    #     return referenceObjV


# class MyProblem(ea.Problem):  # 继承Problem父类
#     def __init__(self, data, index_length, ec):
#         name = 'MyProblem'  # 初始化name（函数名称，可以随意设置）
#         M = 1  # 初始化M（目标维数）
#         maxormins = [1]  # 初始化maxormins（目标最小最大化标记列表，1：最小化该目标；-1：最大化该目标）
#         Dim = index_length  # 初始化Dim（决策变量维数）
#         varTypes = [1] * Dim  # 初始化varTypes（决策变量的类型，元素为0表示对应的变量是连续的；1表示是离散的）
#         lb = [data[0]] * Dim  # 决策变量下界
#         ub = [data[1]] * Dim  # 决策变量上界
#         lbin = [1] * Dim  # 决策变量下边界（0表示不包含该变量的下边界，1表示包含）
#         ubin = [1] * Dim  # 决策变量上边界（0表示不包含该变量的上边界，1表示包含）
#         # 调用父类构造方法完成实例化
#         ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)
#         self.left_index = data[0]
#         self.right_index = data[1]
#         self.Hs = data[2]
#         self.ec = ec
#
#     def aimFunc(self, pop):  # 目标函数
#         Vars = pop.Phen  # 得到决策变量矩阵
#         x = Vars.astype(int)  # 得到决策变量矩阵
#         left_indexs = self.left_index
#         Hs = self.Hs
#         right_indexs = self.right_index
#         # x = np.sort(x)
#         LeftX = x[:, :left_indexs]
#         rightX = x[:, left_indexs:]
#         # print('leftindex,rightindex',left_indexs,right_indexs)
#         row, col = x.shape
#         capity = np.zeros(row)
#         dist = np.ones(row) * 100000000
#         # print('left',LeftX.shape)
#         for i in range(row):
#             X = x[i, :]
#             X = np.sort(X)
#             for j in range(left_indexs):
#                 capity[i] += Hs[X[j]]
#                 dist[i] += np.sum(Hs[:X[j]]) + Hs[X[j]] / 2
#             for j in range(left_indexs, len(X)):
#                 capity[i] += Hs[X[j]]
#                 dist[i] += np.sum(Hs[X[j]:]) + Hs[X[j]] / 2
#
#         # pop.CV = Hs[]
#         # print('oper',opera.shape)
#         pop.CV = self.ec - np.array([capity]).T
#         pop.ObjV = np.vstack([dist]).T  # 计算目标函数值，赋值给pop种群对象的ObjV属性
#
#     # def calReferObjV(self):  # 设定目标数参考值（本问题目标函数参考值设定为理论最优值）
#     #     referenceObjV = np.array([[2.5]])
#     #     return referenceObjV
#

def jijue(data, totalindex, ec):
    """===============================实例化问题对象==========================="""
    problem = MyProblem(data, totalindex, ec)  # 生成问题对象
    """=================================种群设置==============================="""
    Encoding = 'P'  # 编码方式
    NIND = 200  # 种群规模
    Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges, problem.borders)  # 创建区域描述器
    population = ea.Population(Encoding, Field, NIND)  # 实例化种群对象（此时种群还没被初始化，仅仅是完成种群对象的实例化）
    """===============================算法参数设置============================="""
    myAlgorithm = ea.moea_NSGA2_templet(problem, population)  # 实例化一个算法模板对象
    # myAlgorithm.mselecting = 'etour'
    myAlgorithm.mutOper.Pm = 0.1  # 修改变异算子的变异概率
    myAlgorithm.recOper.XOVR = 0.3  # 修改交叉算子的交叉概率
    myAlgorithm.MAXGEN = 1000  # 最大进化代数
    myAlgorithm.verbose = False  # 设置是否打印输出日志信息
    myAlgorithm.drawing = 0  # 设置绘图方式（0：不绘图；1：绘制结果图；2：绘制目标空间过程动画；3：绘制决策空间过程动画）
    """==========================调用算法模板进行种群进化======================="""
    [NDSet, population] = myAlgorithm.run()  # 执行算法模板，得到非支配种群以及最后一代种群
    # NDSet.save()  # 把非支配种群的信息保存到文件中
    """==================================输出结果=============================="""
    print('用时：%s 秒' % myAlgorithm.passTime)
    print('最有个体', NDSet.ObjV)
    print('值', NDSet.Phen)
    print('非支配个体数：%d 个' % NDSet.sizes)
    # print(NDSet.Phen[0]*P)
    if NDSet.sizes != 0:
        print(np.sort(NDSet.Phen[0]))
        # print(NDSet.ObjV)
        # print('P',data[0])
        # Px = NDSet.Phen[0] * data[0]
        # Zx = NDSet.Phen[0] * data[1]
        # Px = Px[Px != 0]
        # Zx = Zx[Zx != 0]
        # data = [Px, Zx, data[2]]
        # print('此时的参数', Px)
        return NDSet.Phen[0], NDSet.ObjV, NDSet
    else:
        print('没有找到可行解！')
        return data, 100000000


def Find_Insert(H, img, ecfinal, label, cor, flag):
    PZlist = []
    LRlist = []
    secret = secret_msg(512, 512)
    ec = 0
    ec2 = 0
    dist2 = 0
    dist = 0
    singlec = np.ceil(ecfinal / 4)
    print('长度', len(H[:, 0]))
    for i in range(len(H[:, 0])):
        print('第{}轮'.format(i))
        Hs = H[i, :]
        Px = np.where(Hs != 0)[0]
        LeftIndex = Px[0]
        RightIndex = Px[-1]
        total_index = Px[0] - Px[-1] + 256
        LRlist.append([LeftIndex, RightIndex, total_index])
        data = [LeftIndex, RightIndex, Hs]
        if i == 1:
            Bins, aa, NDSet = jijue(data, total_index, 2 * singlec)
        else:
            Bins, aa, NDSet = jijue(data, total_index, singlec)
        print('此时', Bins)
        Bins = np.sort(Bins)
        for j in range(len(Bins)):
            ec += Hs[Bins[i]]
        for k in range(LeftIndex):
            dist += np.sum(Hs[:Bins[k]]) + Hs[Bins[k]] / 2
        for k in range(LeftIndex, total_index):
            dist += np.sum(Hs[Bins[k]:]) + Hs[Bins[k]] / 2
        # print(aa)
        PZlist.append(Bins)
        img, singleec, singledist = img_shift2(img, Bins, LeftIndex, secret, label, cor, i, flag)
        print('这一轮容量', singleec)
        print('这一轮失真', singledist)

        ec2 += singleec
        dist2 += singledist
    #     if aa !=0:
    #         PZlist.append(Bins)
    #         img = img_shift(img, Bins, LeftIndex, secret)
    #     else:
    #         PZlist.append([])
    return img, ec, dist, ec2, dist2


def secret_msg(row, col):
    '''

    :param ec: 需要嵌入的容量
    :return: 生成随机生成的二进制
    '''
    arr = np.arange(row * col)
    np.random.shuffle(arr)
    secret_msg = np.zeros((row, col))
    for i in range(row):
        for j in range(col):
            # secret_msg[i, j] = np.mod(arr[col*(i+1)-j-1],2)
            secret_msg[i, j] = np.mod(arr[col * (i + 1) - j - 1], 2)
    return secret_msg


def img_shift(img_data, bins, leftindex, secret, label, cor, epcho, flag):
    row, col = img_data.shape
    Left = bins[0:leftindex]
    Right = bins[leftindex:]
    print('left', Left)
    print('right', Right)
    # Left = getModifyMap(Left, 0)
    # Right = getModifyMap(Right, 1)
    # print('left2', Left)
    # print('right2', Right)
    singleec = 0
    singledist = 0
    # for k in range(len(Left) - 1, -1, -1):
    for k in range(len(Left)):
        index = 0
        for i1 in range(2, row - 2):
            for j in range(2, col - 2):
                cor = np.array(cor)
                index2 = np.where(cor == label[index])[0][0]
                if np.mod(i1 + j, 2) == 0 and flag == 0:
                    if img_data[i1][j] < Left[k] and epcho == index2:
                        img_data[i1][j] -= 1
                        singledist += 1
                    if img_data[i1][j] == Left[k] and epcho == index2:
                        img_data[i1][j] -= secret[i1][j]
                        singleec += 1
                    index += 1
                if np.mod(i1 + j, 2) == 1 and flag == 1:
                    if img_data[i1][j] < Left[k] and epcho == index2:
                        img_data[i1][j] -= 1
                        singledist += 1
                    if img_data[i1][j] == Left[k] and epcho == index2:
                        img_data[i1][j] -= secret[i1][j]
                        singleec += 1

                    index += 1
    # for k2 in range(len(Right)):
    for k2 in range(len(Right) - 1, -1, -1):
        index = 0
        for i2 in range(2, row - 2):
            for j2 in range(2, col - 2):
                cor = np.array(cor)
                index2 = np.where(cor == label[index])[0][0]
                if np.mod(i2 + j2, 2) == 0 and flag == 0:
                    if img_data[i2][j2] > Right[k2] and epcho == index2:
                        img_data[i2][j2] += 1
                        singledist += 1
                    if img_data[i2][j2] == Right[k2] and epcho == index2:
                        img_data[i2][j2] += secret[i2][j2]
                        singleec += 1
                    index += 1
                if np.mod(i2 + j2, 2) == 1 and flag == 1:
                    if img_data[i2][j2] > Right[k2] and epcho == index2:
                        img_data[i2][j2] += 1
                        singledist += 1
                    if img_data[i2][j2] == Right[k2] and epcho == index2:
                        img_data[i2][j2] += secret[i2][j2]
                        singleec += 1
                    index += 1
    return img_data, singleec, singledist


def img_shift2(img_data, bins, leftindex, secret, label, cor, epcho, flag):
    row, col = img_data.shape
    Left = bins[0:leftindex]
    Right = bins[leftindex:]
    print('left', Left)
    print('right', Right)
    # Left = getModifyMap(Left, 0)
    # Right = getModifyMap(Right, 1)
    # print('left2', Left)
    # print('right2', Right)
    singleec = 0
    singledist = 0
    # for k in range(len(Left) - 1, -1, -1):
    index = 0
    # types = cor[epcho]
    for i1 in range(2, row - 2):
        for j in range(2, col - 2):
            cor = np.array(cor)
            # index2 = np.where(cor == label[index])[0][0]

            for k in range(len(Left)):
                if np.mod(i1 + j, 2) == 0 and flag == 0:
                    if img_data[i1][j] < Left[k] and epcho == label[index]:
                        img_data[i1][j] -= 1
                        singledist += 1
                    if img_data[i1][j] == Left[k] and epcho == label[index]:
                        img_data[i1][j] -= secret[i1][j]
                        singleec += 1
                if np.mod(i1 + j, 2) == 1 and flag == 1:
                    if img_data[i1][j] < Left[k] and epcho == label[index]:
                        img_data[i1][j] -= 1
                        singledist += 1
                    if img_data[i1][j] == Left[k] and epcho == label[index]:
                        img_data[i1][j] -= secret[i1][j]
                        singleec += 1
            if flag == 0 and np.mod(i1+j,2) == 0:
                index +=1
            if flag == 1 and np.mod(i1+j,2) == 1:
                index +=1
    # for k2 in range(len(Right)):
    print('Leftec',singleec)
    index = 0
    for i2 in range(2, row - 2):
        for j2 in range(2, col - 2):
            cor = np.array(cor)

            for k2 in range(len(Right) - 1, -1, -1):
                if np.mod(i2 + j2, 2) == 0 and flag == 0:
                    if img_data[i2][j2] > Right[k2] and epcho == label[index]:
                        img_data[i2][j2] += 1
                        singledist += 1
                    if img_data[i2][j2] == Right[k2] and epcho == label[index]:
                        img_data[i2][j2] += secret[i2][j2]
                        singleec += 1

                if np.mod(i2 + j2, 2) == 1 and flag == 1:
                    if img_data[i2][j2] > Right[k2] and epcho == label[index]:
                        img_data[i2][j2] += 1
                        singledist += 1
                    if img_data[i2][j2] == Right[k2] and epcho == label[index]:
                        img_data[i2][j2] += secret[i2][j2]
                        singleec += 1
    if flag == 0 and np.mod(i1 + j, 2) == 0:
        index += 1
    if flag == 1 and np.mod(i1 + j, 2) == 1:
        index += 1
    print('total', singleec)
    return img_data, singleec, singledist


def getModifyMap(P, types):
    P = np.sort(P)
    if types == 0:
        for i in range(len(P) - 1):
            P[i] -= len(P) - 1 - i
    if types == 1:
        for i in range(1, len(P)):
            P[i] += i
    return P


def img_hs(img_data):
    row, col = img_data.shape
    Hs = np.zeros(256)
    for i in range(row):
        for j in range(col):
            Hs[img_data[i][j]] += 1
    return Hs


def plt_make2(data):
    plt.xticks(np.linspace(0, 255, 6, endpoint=True))
    plt.hist(data, bins=255, color='steelblue', align='mid', rwidth=0.8)
    plt.title('Lena')
    plt.xlabel('Pixels', color='#1C2833')
    plt.ylabel('Occurence frequency', color='#1C2833')
    # plt.figure(figsize=(15, 5), dpi=80)
    # if type == 0:
    #     plt.bar(x, y, align='center',color='red')
    plt.show()


def plt_make3(data, title):
    a = np.arange(256)
    plt.xticks(np.linspace(0, 255, 6, endpoint=True))
    plt.hist(data, bins=255, color='steelblue', align='mid', rwidth=0.8)
    plt.title(title)
    plt.xlabel('Pixels', color='#1C2833')
    plt.ylabel('Occurence frequency', color='#1C2833')
    # plt.figure(figsize=(15, 5), dpi=80)
    # if type == 0:
    #     plt.bar(x, y, align='center',color='red')
    plt.show()


def hist_make(img):
    row, col = img.shape
    hist = np.zeros(row * col)
    index = 0
    for i in range(row):
        for j in range(col):
            hist[index] = img[i][j]
            index += 1
    return hist


def make_hs2(label, ks, img, flag, cor):
    row, col = img.shape
    index = 0
    his1 = []
    his2 = []
    his3 = []
    for i in range(2, row - 2):
        for j in range(2, col - 2):
            cor = np.array(cor)
            index2 = np.where(cor == label[index])[0][0]
            if np.mod(i + j, 2) == 0 and flag == 0:
                if index2 == 1:
                    his1.append(img[i][j])
                if index2 == 2:
                    his2.append(img[i][j])
                if index2 == 3:
                    his3.append(img[i][j])
                index += 1
            if np.mod(i + j, 2) == 1 and flag == 1:
                if index2 == 1:
                    his1.append(img[i][j])
                if index2 == 2:
                    his2.append(img[i][j])
                if index2 == 3:
                    his3.append(img[i][j])
                index += 1
    return his1, his2, his3
